package com.explorex.infra.puma.gateway.netty.common.utils;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;

@Slf4j
public class JacksonObjectMapper {

    private static final ObjectMapper objectMapper = new ObjectMapper()
            .setSerializationInclusion(JsonInclude.Include.NON_NULL)
            .configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
            .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);


    public static <T> T loadObject(String jsonStr, Class<T> loadTo) throws JSONObjectMapperException {
        try {
            return objectMapper.readValue(jsonStr, loadTo);
        } catch (IOException e) {
            log.error("JSON loading " + jsonStr + " failed: " + e.getMessage(), e);
            throw new FailedToLoadObjectException();
        }
    }

    public static <T> T loadObjectUnchecked(String jsonStr, Class<T> loadTo) {
        try {
            return objectMapper.readValue(jsonStr, loadTo);
        } catch (IOException e) {
            log.error("JSON loading " + jsonStr + " failed: " + e.getMessage(), e);
            return null;
        }
    }

    public static JsonNode getJsonTree(String jsonStr) throws IOException {

        return objectMapper.readTree(jsonStr);
    }

    public static String dumpObject(Object object) throws JSONObjectMapperException {
        try {
            return objectMapper.writeValueAsString(object);
        } catch (IOException e) {
            log.error("JSON dumping " + object + " failed: " + e.getMessage(), e);
            throw new FailedToDumpObjectException();
        }
    }

    public static String dumpObjectUnchecked(Object object) {
        try {
            return objectMapper.writeValueAsString(object);
        } catch (IOException e) {
            log.error("JSON dumping " + object + " failed: " + e.getMessage(), e);
            return null;
        }
    }

    public static <T> T loadObject(String jsonStr, TypeReference<T> type) throws JSONObjectMapperException {
        try {
            return objectMapper.readValue(jsonStr, type);
        } catch (IOException e) {
            log.error("JSON loading " + jsonStr + " failed: " + e.getMessage(), e);
            throw new FailedToLoadObjectException();
        }
    }

    // Exceptions
    public static class JSONObjectMapperException extends Exception {
    }

    public static class FailedToLoadObjectException extends JSONObjectMapperException {
    }

    public static class FailedToDumpObjectException extends JSONObjectMapperException {
    }
}
